/*
 * main.cpp
 * 主程序入口
 * 功能：
 * 1. 程序流程控制
 * 2. 用户界面交互
 * 3. 调用其他模块功能
 * 4. 错误处理和日志记录
 */

#pragma once
#include <opencv2/opencv.hpp>
#include <iostream>
#include <fstream>
#include <filesystem>
#include <queue>
#include <cmath>
#include <cstdlib>
#include <string>
#include <opencv2/opencv.hpp>   
#include <opencv2\core\core.hpp>
#include <stdio.h>
#include <sstream>
#include "opencv2/imgproc/imgproc.hpp"
#include <opencv2/highgui/highgui_c.h>
#include "opencv2/highgui/highgui.hpp"
#include <vector>
#include <fstream>                   
#include <algorithm>       
#include <windows.h>
#include <iomanip>
#include <chrono>  
#include <thread>  
#include <sstream>  
#include <ctime>
#include <opencv2/opencv.hpp>
#include <iostream>    
#include <opencv2\core\core.hpp>
#include <stdio.h>
#include <string>
#include <sstream>
#include "opencv2/imgproc/imgproc.hpp"
#include <opencv2/highgui/highgui_c.h>
#include "opencv2/highgui/highgui.hpp"
#include "image2bin.h"
#include "qrlocation.h"
#include "vid_to_pic.h"

using namespace std;
using namespace cv;
namespace fs = std::filesystem;
using namespace fs;



void vtop(const std::string& videoPath)
{


    double value = 30;
    std::string sframe = std::to_string(value);
    // ļ  
    const std::string outputDir = "Srcimage";
    // ļУ  
    std::filesystem::create_directories(outputDir);

    // ffmpegʹ-r 1֡Ϊ1֡ÿ  
    // ҽͼƬScrimageļ  
    std::string ffmpegCmd = "ffmpeg -i \"" + videoPath + "\" -r " + sframe + " \"" + outputDir + "/image_%03d.jpg\"";
    // ִffmpeg  
    int result = std::system(ffmpegCmd.c_str());

    // ִн  
    if (result == 0) {
        std::cout << "Successful" << std::endl;
    }
    else {
        std::cout << "Error" << std::endl;
    }
}



Mat src_gray;
Mat dst, detected_edges;
int lowThreshold = 80;
int ratio1 = 3;
int kernel_size = 3;
int highThreshold = lowThreshold * ratio1;
int idx = 0;
Mat temp;

Mat DetectEdge(Mat& src);//ڱԵ̽⣬Զάİɫ߿̽
Mat Binarization(Mat src);
void ErodeAndDilate(Mat& src, Mat& dst);
vector<Point> CutPoly(Mat& src, Mat& dst);
Mat PerspectTrans(Mat src, vector<Point> point);
vector<Mat> QRcode(vector<Mat>& src_ims);


Mat Binarization(Mat src) {
    for (int i = 0; i < src.rows; i++) {
        for (int j = 0; j < src.cols; j++) {
            src.ptr<uchar>(i)[j] = (src.ptr<uchar>(i)[j] > 128 ? 255 : 0);
        }
    }
    return src;
}//ֵ,ÿؽ

Mat DetectEdge(Mat& src)
{
    bilateralFilter(src_gray, detected_edges, 5, 200, 200, BORDER_REFLECT_101);
    //bilateralFilterڶsrc_grayͼ˫˲洢detected_edgesС
    //˫˲һֿڱԵͬʱ˲
    Canny(detected_edges, detected_edges, lowThreshold, highThreshold, kernel_size);
    //CannyһıԵ㷨մͼdetected_edges⵽ıԵٴдdetected_edges
    //lowThresholdhighThresholdCannyֵkernel_sizeSobelӵĴС
    dst = Scalar::all(0);
    //½һڲ
    src.copyTo(dst, detected_edges);
    //ѱԵ̽õĿ򿽱ڲ
    return dst;
}//Ե̽⺯Ҫ̽ɫ

void ErodeAndDilate(Mat& src, Mat& dst)
{
    Mat element = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
    //һдһṹԪأͺ͸ʴ
    //getStructuringElementһΣMORPH_RECT״ĺˣСΪ3x3Point(-1, -1)ʾ˵êں˵ġ
    dilate(src, dst, element);
    erode(dst, dst, element);
    //ȶԭͼһ͸ʴȻ󴫸dst
    for (int i = 0; i < 8; i++)
    {
        dilate(dst, dst, element);
        erode(dst, dst, element);
    }//ʵ̫ӰimgٶȣЧظ8μ
}//ͼ͡ʴ

vector<Point> CutPoly(Mat& src, Mat& dst)
{
    double maxarea = 0;
    int maxAreaIdx = 0;
    vector<vector<Point>>contours;
    vector<Vec4i>hierarchy;
    findContours(src, contours, hierarchy, cv::RETR_TREE, cv::CHAIN_APPROX_SIMPLE, Point(0, 0));
    //findContours opencvԴ⺯ڶֵֵͼҵϢӦ
//		//`contours`ͼм⵽ÿı߽ϵĵ㡣ÿһаһϵеĵ㣬Щγı߽硣
//		//`hierarchy`ĲϢ`findContours`Уָ`RETR_TREE`ʾ
//		// ÿԪ`hierarchy[i]`ĸֱֵʾǰĺһǰһ͸
    for (int i = 0; i < contours.size(); i++)
    {
        double tmparea = fabs(contourArea(contours[i]));
        if (tmparea > maxarea)
        {
            maxarea = tmparea;
            maxAreaIdx = i;
            continue;
        }
    }//ҵ
    vector<Point>vertex_point;
    approxPolyDP(contours[maxAreaIdx], vertex_point, 50, 1);
    //ʹDouglas-Peucker㷨ΪΣ50ǽƵľȣ1ʾ߱պϡ
    //εĶ
    return vertex_point;
}


Mat PerspectTrans(Mat src, vector<Point> point)
{
    Point2f SrcPoints[4];
    Point2f DstPoints[4];

    bool x[4] = { false,false,false,false };
    bool y[4] = { false,false,false,false };
    float x_tmp1;
    float x_tmp2;
    int idx11;
    int idx12;
    if (point[0].x < point[1].x)
    {
        x_tmp1 = point[0].x;
        idx11 = 0;
        x_tmp2 = point[1].x;
        idx12 = 1;
    }
    else
    {
        x_tmp1 = point[1].x;
        idx11 = 1;
        x_tmp2 = point[0].x;
        idx12 = 0;
    }

    for (int i = 2; i < 4; i++)
    {
        if (point[i].x < x_tmp2)
        {
            if (point[i].x < x_tmp1)
            {
                x_tmp2 = x_tmp1;
                idx12 = idx11;
                x_tmp1 = point[i].x;
                idx11 = i;
            }
            else
            {
                x_tmp2 = point[i].x;
                idx12 = i;
            }
        }
    }
    x[idx11] = true;
    x[idx12] = true;
    float y_tmp1;
    float y_tmp2;
    int idx21;
    int idx22;
    if (point[0].y < point[1].y)
    {
        y_tmp1 = point[0].y;
        idx21 = 0;
        y_tmp2 = point[1].y;
        idx22 = 1;
    }
    else
    {
        y_tmp1 = point[1].y;
        idx21 = 1;
        y_tmp2 = point[0].y;
        idx22 = 0;
    }

    for (int i = 2; i < 4; i++)
    {
        if (point[i].y < y_tmp2)
        {
            if (point[i].y < y_tmp1)
            {
                y_tmp2 = y_tmp1;
                idx22 = idx21;
                y_tmp1 = point[i].y;
                idx21 = i;
            }
            else
            {
                y_tmp2 = point[i].y;
                idx22 = i;
            }
        }
    }
    y[idx21] = true;
    y[idx22] = true;

    for (int i = 0; i < 4; i++)
    {
        if (x[i] && y[i])
        {
            SrcPoints[0].x = point[i].x;
            SrcPoints[0].y = point[i].y;
        }
        else if (x[i] && !y[i])
        {
            SrcPoints[1].x = point[i].x;
            SrcPoints[1].y = point[i].y;
        }
        else if (!x[i] && !y[i])
        {
            SrcPoints[2].x = point[i].x;
            SrcPoints[2].y = point[i].y;
        }
        else
        {
            SrcPoints[3].x = point[i].x;
            SrcPoints[3].y = point[i].y;
        }
    }
    DstPoints[0] = Point(0, 0);
    DstPoints[1] = Point(0, 1000);
    DstPoints[2] = Point(1600, 1000);
    DstPoints[3] = Point(1600, 0);

    Mat warpmatrix = getPerspectiveTransform(SrcPoints, DstPoints);

    Mat res;

    warpPerspective(src, res, warpmatrix, res.size(), INTER_LANCZOS4);

    Rect res_rect(0, 0, 1600, 1000);
    res = res(res_rect);

    return res;
}//͸ӱ任,α任һ

vector<Mat> QRcode(vector<Mat>& Images)
{
    vector<Mat> src;
    for (auto image : Images)
    {
        if (!image.data)
            exit(-1);//ͼûϢ˳
        resize(image, image, Size(1600, 1000), 0, 0, INTER_LANCZOS4);
        //ͼСе
        //ڲͬСĶάѵͼСûѡôСܻʶʧ
        //ڲ

        temp.create(image.size(), image.type());
        cvtColor(image, src_gray, cv::COLOR_BGR2GRAY);
        temp = DetectEdge(image);
        cvtColor(temp, temp, cv::COLOR_BGR2GRAY);
        ErodeAndDilate(temp, temp);
        vector<Point>point = CutPoly(temp, temp);
        //tempдҶȻԵ̽⣬͸ʴ󣬵õĸǵ㲢

        image = PerspectTrans(image, point);
        //ĸǵ͸ӱ任ͼУ
        cvtColor(image, image, cv::COLOR_BGR2GRAY);
        //תɻҶͼ
        //image = Binarization(image);
        //ֵ
        idx++;
        cout << idx << ": " << endl << image.rows << " " << image.cols << endl;
        src.push_back(image);
        //
    }
    return src;//شĶάʶͼ
}

bool areImagesEqual(const cv::Mat& image1, const cv::Mat& image2) {
    if (image1.rows != image2.rows || image1.cols != image2.cols || image1.type() != image2.type()) {
        return false;
    }
    cv::Mat diff;
    cv::compare(image1, image2, diff, cv::CMP_NE);
    int nonzeroElements = cv::countNonZero(diff);
    return nonzeroElements == 0;
}

bool isFileSizeOver400KB(const std::string& filePath) {
    std::ifstream file(filePath, std::ifstream::ate | std::ifstream::binary);
    if (!file.is_open()) {
        std::cerr << "޷ļ: " << filePath << std::endl;
        return false;
    }

    //ȡļС
    const long fileSize = file.tellg();
    file.close();

    //ļСǷ񳬹500KB
    return fileSize > 400 * 1024;
}
void qrlocation() {
    vector<Mat> SrcImages;
    vector<Mat> DstImages;

    String picname = "./Srcimage/*.jpg";//ͨƥļµͼƬע޸ĺ׺

    vector<String>image_files;
    glob(picname, image_files);
    for (int i = 0; i < image_files.size(); i++)
    {
        Mat tmp = imread(image_files[i]);
        if (tmp.data)
            SrcImages.push_back(tmp);
    }

    DstImages = QRcode(SrcImages);

    int j = 0;//ʾЧ֡
    for (int i = 0; i < DstImages.size(); i++)
    {
        DstImages[i] = Binarization(DstImages[i]);
        //bilateralFilter(dst_images[i], dst_images[i], 5, 200, 200, BORDER_REFLECT_101);
        GaussianBlur(DstImages[i], DstImages[i], Size(7, 7), 0);



        string temp = "temp.png";
        imwrite(temp, DstImages[i]);
        if (isFileSizeOver400KB(temp)) {
            if (i > 0 && areImagesEqual(DstImages[i], DstImages[i - 1]))continue;//ȥ
            char str[10];
            sprintf_s(str, "%u.png", ++j);
            string tmp = "./Dst_image/";
            string strSaveName = tmp + str;

            cout << strSaveName << endl;
            imwrite(strSaveName, DstImages[i]);

        }
        else continue;


        //Ҫ֡еĶάлҶ˲Ħƺ;

    }
    cout << "!" << endl;
    waitKey(0);

    return;
}




bool is_number(const std::string& str) {
    for (char c : str) {
        if (!std::isdigit(c)) return false;
    }
    return true;
}




//const int whiteBlockWidth = 8;
//const int sideSize = 50 * whiteBlockWidth;
//double rowWidth;
//double colWidth;
//double rowoffset;
//double coloffset;
//bool error_row[42];
//bool error_col[42];
//const int squareSize = 7 * whiteBlockWidth;
//const int blockSize = 3 * whiteBlockWidth;
//const int dataBegin = 8 * whiteBlockWidth;
//const int dataSize = (sideSize - dataBegin) / whiteBlockWidth;//42
//queue <short> indata;
//
//int getfilenum(string folderpath) {
//    int filenum = 0;
//    for (const auto& entry : fs::directory_iterator(folderpath))
//        if (entry.is_regular_file())
//            filenum++;
//    return filenum;
//}
//int getcolor(Mat& image, int row, int column) {
//    int whitenum = 0;
//    cv::Vec3b color;
//    for (int i = 0; i < rowWidth; i++)
//        for (int j = 0; j < colWidth; j++) {
//            color = image.at<cv::Vec3b>(row + i + rowoffset, column + j + coloffset);
//            if (static_cast<int>(color[0]) + static_cast<int>(color[1]) + static_cast<int>(color[2]) > 382)
//                whitenum++;
//        }
//    return (whitenum > rowWidth * colWidth / 2 ? 0 : 1);
//}
//int getno(Mat& image) {
//    int a[16] = { 0 };
//    int no = 0;
//    for (int i = 0; i < 16; i++) {
//        a[i] = getcolor(image, 0, (8 + i) * colWidth);
//        no *= 2;
//        no += a[i];
//    }
//    return no;
//}
//int getsize(Mat& image) {
//    int a[16] = { 0 };
//    int size = 0;
//    for (int i = 0; i < 16; i++) {
//        a[i] = getcolor(image, 0, (26 + i) * colWidth);
//        size *= 2;
//        size += a[i];
//    }
//    return size;
//}
//void getdata(Mat& image, short data[]) {
//    if (!image.empty())
//        for (int i = 0; i < dataSize; i++)
//            for (int j = 0; j < dataSize; j++)
//                data[i * dataSize + j] = getcolor(image, (8 + i) * rowWidth, (8 + j) * colWidth);
//}
//void getcode(Mat& image, short code[]) {
//    if (!image.empty()) {
//        for (int i = 0; i < 12; i++)
//            for (int j = 0; j < 7; j++)
//                code[i * 7 + j] = getcolor(image, (8 + i) * rowWidth, (0 + j) * colWidth);
//    }
//}
//bool check(short data[], short code[]) {
//    int res = 0;
//    bool ret = true;
//    for (int i = 0; i < dataSize; i++) {//У
//        res = 0;
//        for (int j = 0; j < dataSize; j++)
//            res = res ^ data[i * dataSize + j];
//        res = res ^ code[i];
//        if (res) {
//            error_row[i] = 1;
//            ret = false;
//        }
//    }
//    for (int i = 0; i < dataSize; i++) {//У
//        res = 0;
//        for (int j = 0; j < dataSize; j++)
//            res = res ^ data[i + dataSize * j];
//        res = res ^ code[dataSize + i];
//        if (res) {
//            error_col[i] = 1;
//            ret = false;
//        }
//    }
//    return ret;
//}
//
//unsigned char bit2byte() {
//    unsigned char ret = 0;
//    for (int i = 0; i < 8; i++) {
//        ret *= 2;
//        if (!indata.empty()) {
//            ret += indata.front();
//            indata.pop();
//        }
//    }
//    return ret;
//}
//
//void dedup() {
//    string folderpath = "Dst_image";
//    int filenum = getfilenum(folderpath);
//    int pre = -1, now = -1;
//    string filepath;
//    Mat image;
//    for (int i = 1; i <= filenum; i++) {
//        filepath = folderpath + "\\" + to_string(i) + ".png";
//        image = imread(filepath);
//        rowWidth = image.rows * 1.0 / 54;
//        colWidth = image.cols * 1.0 / 54;
//        rowoffset = 2 * rowWidth;
//        coloffset = 2 * colWidth;
//        now = getno(image);
//        if (now == pre)
//            remove(filepath);//ȥ
//        else if (now == pre + 1)
//            rename(filepath, folderpath + "\\"  + to_string(now + 1) + ".png");
//        else if (now > pre + 1)
//            cerr << "֡ʶ֡" << endl;
//        pre = now;
//    }
//}
//void writetobin(string binpath) {
//    std::fstream file(binpath, ios::out | ios::binary);
//    if (!file.is_open())
//        std::cerr << "Failed to create file." << std::endl;
//    int size = ceil(indata.size() / 8);
//    for (int i = 0; i < size; i++) {
//        unsigned char data = bit2byte();
//        file.write(reinterpret_cast<const char*>(&data), 1);
//    }
//    file.close();
//}
//
//
//void img2bin(string binpath)
//{
//    string folderpath = "Dst_image";
//    dedup();
//    int filenum = getfilenum(folderpath);
//    short data[2000], code[100];
//    for (int i = 1; i <= filenum; i++) {
//        /*string filepath = folderpath + "\\" + to_string(i) + ".png";*/
//        string filepath = folderpath + "\\" + to_string(i) + ".png";
//        Mat image = imread(filepath);
//        rowWidth = image.rows * 1.0 / 54;
//        colWidth = image.cols * 1.0 / 54;
//        rowoffset = 2 * rowWidth;
//        coloffset = 2 * colWidth;
//        getdata(image, data);
//        getcode(image, code);
//        /*if (!check(data, code))
//            correct(data, code);*/
//        if (!check(data, code))
//            cout << "" << i << "ͼƬϢ" << endl;
//        int size = getsize(image);
//        for (int i = 0; i < size; i++)
//            indata.push(data[i]);
//    }
//    writetobin(binpath);
//    cout << "The bin file has generated successfully!" << endl;
//}


std::uintmax_t getFileSize(const fs::path& filePath) {
    return fs::file_size(filePath);
}

// ļǷС800KB  
bool isFileLessThan800KB(const fs::path& filePath) {
    return getFileSize(filePath) < 800 * 1024; // 800KB in bytes  
}

// ȥDst_imageļС800KBͼƬʣͼƬ  
void removeSmallImagesAndRenameRemaining() {
    fs::path dstImagePath = "Dst_image";

    if (!fs::exists(dstImagePath) || !fs::is_directory(dstImagePath)) {
        std::cerr << "The directory does not exist or is not a directory: " << dstImagePath << std::endl;
        return;
    }

    // ռд800KBPNGļ·  
    std::vector<fs::path> pngFiles;
    for (const auto& entry : fs::recursive_directory_iterator(dstImagePath)) {
        if (entry.is_regular_file() && entry.path().extension() == ".png") {
            if (!isFileLessThan800KB(entry.path())) {
                pngFiles.push_back(entry.path());
            }
            else {
                fs::remove(entry.path());
                std::cout << "Removed: " << entry.path() << std::endl;
            }
        }
    }

    // ûʣļ˳  
    if (pngFiles.empty()) {
        std::cout << "No images remaining after removing small files." << std::endl;
        return;
    }

    // ʣͼƬ  
    for (size_t i = 0; i < pngFiles.size(); ++i) {
        fs::path newPath = dstImagePath / (std::to_string(i + 1) + ".png");
        fs::rename(pngFiles[i], newPath);
        std::cout << "Renamed: " << pngFiles[i] << " to " << newPath << std::endl;
    }
}

// 修改全局变量定义，避免与image2bin.h冲突
const int whiteBlockWidth = 5;
const int offset = 2 * whiteBlockWidth;
const int sideHeight = 156 * whiteBlockWidth + 2 * offset;
const int sideWidth = 96 * whiteBlockWidth + 2 * offset;
const int squareSize = 7 * whiteBlockWidth;
const int blockSize = 3 * whiteBlockWidth;
const int dataBegin = 8 * whiteBlockWidth + offset;
const int sideSize = 50 * whiteBlockWidth;
double rowWidth;
double colWidth;
double rowoffset;
double coloffset;
// 删除以下行，使用image2bin.h中的error_row和error_col
// bool error_row[100];
// bool error_col[150];
short bindata[15000];
short code[400];
// queue <short> indata; 这个在image2bin.h中已定义，这里不再重复定义

// 重命名这个函数，避免与image2bin.h中的getfilenum冲突
int main_getfilenum(string folderpath) {
    int filenum = 0;
    for (const auto& entry : fs::directory_iterator(folderpath))
        if (entry.is_regular_file())
            filenum++;
    return filenum;
}
int getcolor(Mat& image, int row, int column) {
    int whitenum = 0;
    cv::Vec3b color;
    for (int i = 0; i < rowWidth; i++)
        for (int j = 0; j < colWidth; j++) {
            color = image.at<cv::Vec3b>(row + i + rowoffset, column + j + coloffset);
            if (static_cast<int>(color[0]) + static_cast<int>(color[1]) + static_cast<int>(color[2]) > 382)
                whitenum++;
        }
    return (whitenum > rowWidth * colWidth / 2 ? 0 : 1);
}
int getno(Mat& image) {
    int a[8] = { 0 };
    int no = 0;
    for (int i = 0; i < 8; i++) {
        a[i] = getcolor(image, 8 * rowWidth, i * colWidth);
        no *= 2;
        no += a[i];
    }
    return no;
}
int getsize(Mat& image) {
    int a[16] = { 0 };
    int size = 0;
    for (int i = 0; i < 16; i++) {
        a[i] = getcolor(image, (9 + i / 8) * rowWidth, (i % 8) * colWidth);
        size *= 2;
        size += a[i];
    }
    return size;
}
void getdata(Mat& image, short data[], bool pos) {
    if (!image.empty()) {
        if (pos) {//
            for (int i = 0; i < 96; i++)
                for (int j = 0; j < 140; j++)
                    data[i * 140 + j] = getcolor(image, i * rowWidth, (8 + j) * colWidth);
        }
        else {//С
            for (int i = 0; i < 88; i++)
                for (int j = 0; j < 8; j++)
                    data[13440 + i * 8 + j] = getcolor(image, (8 + i) * rowWidth, (148 + j) * colWidth);
        }
    }
}
void getcode(Mat& image, short code[], bool pos) {
    if (!image.empty()) {
        if (pos) {//
            for (int i = 0; i < 236; i++)
                code[i] = getcolor(image, (i / 8 + 11) * rowWidth, (i % 8) * colWidth);
        }
        else {//С
            for (int i = 0; i < 96; i++)
                code[236 + i] = getcolor(image, (i / 8 + 41) * rowWidth, (i % 8) * colWidth);
        }
    }
}
bool check(short data[], short code[], bool pos) {
    int res = 0;
    bool ret = true;
    if (pos) {//
        for (int i = 0; i < 96; i++) {//У
            res = 0;
            for (int j = 0; j < 140; j++)
                res = res ^ data[i * 140 + j];
            res = res ^ code[i];
            if (res) {
                error_row[i] = 1;
                ret = false;
            }
        }
        for (int i = 0; i < 140; i++) {//У
            res = 0;
            for (int j = 0; j < 96; j++)
                res = res ^ data[i + j * 140];
            res = res ^ code[96 + i];
            if (res) {
                error_col[i] = 1;
                ret = false;
            }
        }
    }
    else {//С
        for (int i = 0; i < 88; i++) {//У
            res = 0;
            for (int j = 0; j < 8; j++)
                res = res ^ data[13440 + i * 8 + j];
            res = res ^ code[236 + i];
            if (res) {
                error_row[i] = 1;
                ret = false;
            }
        }
        for (int i = 0; i < 8; i++) {//У
            res = 0;
            for (int j = 0; j < 88; j++)
                res = res ^ data[13440 + i + 8 * j];
            res = res ^ code[324 + i];
            if (res) {
                error_col[i] = 1;
                ret = false;
            }
        }
    }
    return ret;
}
//void correct(short data[], short code[]) {
//    for (int i = 0; i < dataSize; i++) {
//        if (error_row[i]) {
//            for (int j = 0; j < dataSize; j++) {
//                if (error_col[j]) {
//                    if (data[i * dataSize + j] == 1)
//                        data[i * dataSize + j] = 0;
//                    else
//                        data[i * dataSize + j] = 1;
//                }
//            }
//        }
//    }
//}
unsigned char bit2byte() {
    unsigned char ret = 0;
    for (int i = 0; i < 8; i++) {
        ret *= 2;
        if (!indata.empty()) {
            ret += indata.front();
            indata.pop();
        }
    }
    return ret;
}
void dedup(string folderpath) {
    int filenum = main_getfilenum(folderpath);
    int pre = -1, now = -1;
    string filepath;
    Mat image;
    for (int i = 1; i <= filenum; i++) {
        /*filepath = folderpath + "\\" + "qrcode-" + to_string(i) + ".png";*/
        filepath = folderpath + "\\" + to_string(i) + ".png";
        image = imread(filepath);
        rowWidth = image.rows * 1.0 / 100;
        colWidth = image.cols * 1.0 / 160;
        rowoffset = 2 * rowWidth;
        coloffset = 2 * colWidth;
        now = getno(image);
        cout << pre << " ";
        cout << now << endl;
        if (now == pre)
            remove(filepath);//ȥ
        else if (now == pre + 1)
            /*rename(filepath, folderpath + "\\" + "qrcode-" + to_string(now + 1) + ".png");*/
            rename(filepath, folderpath + "\\" + to_string(now + 1) + ".png");
        else
        {
            cerr << "ͼƬģ" << endl;
            remove(filepath);//ȥ
            continue;
        }
        pre = now;
    }
}
void clear(string binpath) {
    std::ofstream file(binpath, std::ios::out | std::ios::binary);

    if (!file.is_open())
        std::cerr << "Error opening file!" << std::endl;

    file.close();
}
// 重命名这个函数，避免与image2bin.h中的冲突
void main_writetobin(string binpath) {
    std::fstream file(binpath, std::ios::out | std::ios::app | std::ios::binary);
    if (!file.is_open())
        std::cerr << "Failed to create file." << std::endl;
    int size = ceil(indata.size() / 8);
    for (int i = 0; i < size; i++) {
        unsigned char data = bit2byte();
        file.write(reinterpret_cast<const char*>(&data), 1);
    }
    file.close();
}
void main_img2bin(string binpath) {
    string folderpath = "Dst_image";
    dedup(folderpath);
    clear(binpath);
    int filenum = main_getfilenum(folderpath);
    for (int i = 1; i <= filenum; i++) {
        /*string filepath = folderpath + "\\" + "qrcode-" + to_string(i) + ".png";*/
        string filepath = folderpath + "\\" + to_string(i) + ".png";
        Mat image = imread(filepath);
        rowWidth = image.rows * 1.0 / 100;
        colWidth = image.cols * 1.0 / 160;
        rowoffset = 2 * rowWidth;
        coloffset = 2 * colWidth;
        //
        getdata(image, bindata, 1);
        getcode(image, code, 1);
        if (!check(bindata, code, 1))
            std::cout << "" << i << "ͼƬϢ" << endl;
        //С
        getdata(image, bindata, 0);
        getcode(image, code, 0);
        if (!check(bindata, code, 0))
            std::cout << "" << i << "ͼƬϢ" << endl;
        int size = getsize(image);
        for (int i = 0; i < size; i++)
            indata.push(bindata[i]);
        main_writetobin(binpath);
    }
    std::cout << "The bin file has generated successfully!" << endl;
}





void comparecode(string voutFilename) {
    const std::string inFilename = "in.bin";
    const std::string outFilename = "out.bin";

    std::ifstream inFile(inFilename, std::ios::binary);
    std::ifstream outFile(outFilename, std::ios::binary);
    std::ofstream voutFile(voutFilename, std::ios::binary);

    if (!inFile.is_open() || !outFile.is_open() || !voutFile.is_open()) {
        std::cerr << "Error opening files!" << std::endl;
        return;
    }

    std::vector<unsigned char> inBuffer, outBuffer;
    inBuffer.reserve(1024); //ԤһЩռ䣬Ҫ  
    outBuffer.reserve(1024);

    // ȡin.bin  
    unsigned char byte;
    while (inFile.read((char*)&byte, sizeof(byte))) {
        inBuffer.push_back(byte);
    }
    inFile.close();

    // ȡout.bin  
    while (outFile.read((char*)&byte, sizeof(byte))) {
        outBuffer.push_back(byte);
    }
    outFile.close();

    // ȷ  
    size_t maxLength = max(inBuffer.size(), outBuffer.size());

    // λȽϲдvout.bin  
    size_t correctBits = 0;
    for (size_t i = 0; i < maxLength; ++i) {
        unsigned char voutByte = 0;
        unsigned char inByte = (i < inBuffer.size()) ? inBuffer[i] : 0;
        unsigned char outByte = (i < outBuffer.size()) ? outBuffer[i] : 0;

        for (size_t bit = 0; bit < 8; ++bit) {
            bool inBit = (inByte & (1 << bit)) != 0; // λƵķ  
            bool outBit = (outByte & (1 << bit)) != 0; // λƵķ  
            if (inBit == outBit) {
                voutByte |= (1 << bit); // ȣvoutByteĶӦλΪ1  
                ++correctBits; // ȷλ  
            }
            else {
                voutByte &= ~(1 << bit); // ȣȷvoutByteĶӦλΪ0һʵǶģΪvoutByteʼΪ0  
            }
        }
        voutFile.write((char*)&voutByte, sizeof(voutByte));
    }
    voutFile.close();

    // ȷ  
    double correctRate = static_cast<double>(correctBits) / (8 * maxLength);
    std::cout << "Correct rate: " << correctRate * 100 << "%" << std::endl;

    return;
}


void removeAndRenamePngImages() {
    // Dst_imageļ·ĬΪǰ·µDst_imageļ  
    fs::path dstImagePath = fs::current_path() / "Dst_image";

    // Dst_image·ǷΪĿ¼  
    if (!fs::exists(dstImagePath) || !fs::is_directory(dstImagePath)) {
        std::cerr << "Error: The Dst_image directory does not exist." << std::endl;
        return;
    }

    // ȡDst_imageļеpngļ  
    std::vector<fs::path> pngFiles;
    for (const auto& entry : fs::directory_iterator(dstImagePath)) {
        if (entry.is_regular_file() && entry.path().extension() == ".png") {
            pngFiles.push_back(entry.path());
        }
    }

    // ļСɾС500KBͼƬ  
    for (const auto& file : pngFiles) {
        if (fs::file_size(file) < 500 * 1024) {
            fs::remove(file);
            std::cout << "Deleted file: " << file << std::endl;
        }
    }

    pngFiles.clear();
    for (const auto& entry : fs::directory_iterator(dstImagePath)) {
        if (entry.is_regular_file() && entry.path().extension() == ".png") {
            pngFiles.push_back(entry.path());
        }
    }
}

bool is_png_file(const fs::path& p) {
    return p.extension() == ".png";
}

void rename()
{
    std::filesystem::path directory_path = "Dst_image"; // 滻ΪĿ¼·  
    std::vector<std::filesystem::path> png_files;

    // .pngļ  
    for (const auto& entry : std::filesystem::directory_iterator(directory_path)) {
        if (entry.path().extension() == ".png") {
            png_files.push_back(entry.path());
        }
    }

    // ļȷʱ˳ȷ  
    std::sort(png_files.begin(), png_files.end());

    int counter = 1;
    for (const auto& file : png_files) {
        std::filesystem::path new_file_path = directory_path / (std::to_string(counter) + ".png");
        std::filesystem::rename(file, new_file_path);
        std::cout << "Renamed " << file.filename() << " to " << new_file_path.filename() << std::endl;
        ++counter;
    }

    return;
}

int main(int argc, char* argv[]) // argc ǲ, argv ǲ  
{
    if (argc != 4) {
        std::cerr << "usage: project1 s1 s2 s3" << std::endl;
        return 1; // ȷش  
    }

    std::string s1 = argv[1]; // һ  
    std::string s2 = argv[2]; // ڶ  
    std::string s3 = argv[3]; //   

    // vtopƵ  
    vtop("video/" + s1);
    qrlocation();
    main_img2bin(s2);
    comparecode(s3);

    return 0; // ɹִ  
}
//int main()
//{
//    string s1, s2, s3;
//    cin >> s1;
//    cin >> s2;
//    cin >> s3;
//     vtop("video/" + s1);
//    qrlocation();
//    img2bin(s2);
//    comparecode(s3);
//    return 0;
//}
